const fs = require('fs');
const Promise = require('bluebird');
const Sequelize = require("sequelize");
const schema = require('./schema');

module.exports = {
    newInstance: function (mysqlConfig) {
        let sequelize = new Sequelize(mysqlConfig.dbname, mysqlConfig.username, mysqlConfig.password, mysqlConfig.connection);
        let models = {
            sequelize: sequelize,
            associations: {
                relateOne: function (data, model, id_name, obj_name, attributes) {
                    let rows = data.rows || data, ids = [];
                    if (rows && rows.length) {
                        for (let i in rows) {
                            let row = rows[i];
                            if (row[id_name]) {
                                ids.push(row[id_name]);
                            }
                        }
                        if (ids.length) {
                            return model.findAll({
                                where: {id: ids},
                                attributes: attributes,
                                raw: true
                            }).then(function (items) {
                                let map = {};
                                for (let i in items) {
                                    let item = items[i];
                                    map[item.id] = item;
                                }
                                for (let i in rows) {
                                    let row = rows[i];
                                    if (row[id_name]) {
                                        row[obj_name] = map[row[id_name]];
                                    }
                                }
                                return data;
                            });
                        }
                    }
                    return Promise.resolve(data);
                },
                relateMany: function (data, model, id_name, obj_name, attributes, order, where, over_id) {
                    let rows = data.rows || data, ids = [], map = {};
                    if (rows && rows.length) {
                        for (let i in rows) {
                            let row = rows[i], id = (over_id ? row[over_id] : row.id);
                            map[id] = row;
                            ids.push(id);
                            row[obj_name] = [];
                        }
                        if (!where) {
                            where = {};
                        }
                        where[id_name] = ids;

                        return model.findAll({
                            where: where,
                            attributes: attributes,
                            order: order,
                            raw: true
                        }).then(function (items) {
                            for (let i in items) {
                                let item = items[i];
                                map[item[id_name]][obj_name].push(item);
                            }
                            return data;
                        });
                    }
                    return Promise.resolve(data);
                },
                relateManyLimit: function (data, model, id_name, obj_name, attributes, order, limit) {
                    let rows = data.rows || data;
                    if (rows && rows.length) {
                        return Promise.map(rows, function (row) {
                            return model.findAll({
                                where: {[id_name]: row.id},
                                attributes: attributes,
                                limit: limit,
                                order: order,
                                raw: true
                            }).then(function (items) {
                                row[obj_name] = items;
                            });
                        }, {concurrency: 3}).then(function () {
                            return data;
                        });
                    }
                    return Promise.resolve(data);
                }
            }
        };


        /**
         * 初始化实体
         */
        for (let name in schema) {
            let model = schema[name];

            let permissionMap = {};
            for (let key in model) {
                let permissions = model[key].permissions;
                if (permissions && permissions.length) {
                    for (let i in permissions) {
                        let permission = permissions[i];
                        if (!permissionMap[permission]) {
                            permissionMap[permission] = [];
                        }
                        permissionMap[permission].push(key);
                    }
                }
            }

            models[name] = sequelize.define(name, model, {
                createdAt: 'created_at', updatedAt: 'updated_at', timestamps: true, underscored: true
            });
            models[name].permissionMap = permissionMap;
        }

        /**
         * 扩展实体方法
         */
        for (let name in schema) {
            let filename = __dirname + '/extends/' + name + '.js';
            if (fs.existsSync(filename)) {
                require('./extends/' + name)(models);
            }
        }

        return models;
    }
};